from sklearn.datasets import load_boston  # 数据集
from sklearn.linear_model import LinearRegression, SGDRegressor  # 回归
from sklearn.model_selection import train_test_split  # 数据集分割
from sklearn.preprocessing import StandardScaler  # 标准化
from sklearn.metrics import mean_squared_error  # 均方误差
import numpy as np
import matplotlib.pyplot as plt
# 设置中文字体支持
plt.rcParams['font.sans-serif'] = ['SimHei', 'Arial Unicode MS', 'Microsoft YaHei']
plt.rcParams['axes.unicode_minus'] = False

def mylinear():
    """线性回归预测房子价格"""

    # 1、波士顿地区房价数据获取
    boston = load_boston()
    print("数据描述：\n", boston.DESCR)

    # 2、房价数据分割：分割数据集到训练集和测试集 （顺序：训练集特征，测试集特征，训练集标签，测试集标签）
    x_train, x_test, y_train, y_test = train_test_split(boston.data, boston.target, test_size=0.25)
    print("测试集标签：\n", y_test)

    # 3、进行标准化处理
    std_x = StandardScaler()
    x_train = std_x.fit_transform(x_train)
    x_test = std_x.transform(x_test)

    # 目标值
    std_y = StandardScaler()
    y_train = std_y.fit_transform(y_train.reshape(-1, 1))  # 新版本sklearn，单特征或样本需reshape(-1, 1)
    y_test = std_y.transform(y_test.reshape(-1, 1))

    # 4、预测

    # (方法1)最简单的线性回归预测结果
    lr = LinearRegression()
    lr.fit(x_train, y_train)
    print("\n 回归系数:", lr.coef_)

    # 预测测试集的房子价格
    y_predict = lr.predict(x_test)
    y_predict = std_y.inverse_transform(y_predict)  # 转换回标准化之前的数值
    y_predict = y_predict.reshape(-1)  # 转成一维
    print("\n 正规方程测试集里每个房子的预测价格：\n", y_predict)

    print("\n 正规方程线性回归模型的均方误差为：", mean_squared_error(std_y.inverse_transform(y_test),
                                                                     y_predict))

    # (方法2)梯度下降方式预测结果
    sgd = SGDRegressor()
    sgd.fit(x_train, y_train.ravel())  # .ravel()用来转为1维数组
    print("\n 回归系数:", sgd.coef_)

    # 预测测试集的房子价格
    y_sgd_predict = sgd.predict(x_test)
    y_sgd_predict = std_y.inverse_transform(y_sgd_predict)  # 转换回标准化之前的数值
    print("\n 梯度下降测试集里每个房子的预测价格：\n", y_sgd_predict)

    print("\n 梯度下降线性回归模型的均方误差为：", mean_squared_error(std_y.inverse_transform(y_test),
                                                                     y_sgd_predict))

    # 绘图进行比较
    plt.figure(figsize=(10, 7))  # 画布大小
    num = 100
    x = np.arange(1, num + 1)  # 取100个点进行比较
    y_test = std_y.inverse_transform(y_test)
    plt.plot(x, y_test[:num], label='target')  # 目标取值
    plt.plot(x, y_predict[:num], label='preds')  # 预测取值
    plt.legend(loc='upper right')  # 线条显示位置
    plt.show()


if __name__ == "__main__":
    mylinear()

